﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Xml;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using XRM.Sag.Utils.Helpers;
using XRM.Security.DataAccess.Models;
using XRM.Security.WebUI.Enums;
using XRM.Security.WebUI.Helpers;

namespace XRM.Security.WebUI.Models.Template
{
    public static class TemplateFileGenerator
    {
        public static Stream GenerateFileFromTemplateDocument(this DataAccess.Models.Request documentTemplate, PrintFormType type, RequestWorkKind requestWorkKind = null)
        {
            var templateDocument = GetWordTemplate(type.ToString());

            using (WordprocessingDocument wordProcessingDocument = WordprocessingDocument.Open(templateDocument, true))
            {
                MainDocumentPart main = wordProcessingDocument.MainDocumentPart;
                main.DeleteParts(main.CustomXmlParts);

                var dataSource = TemplateSerializer.GetTemplateSerializer(type).Serialize(documentTemplate, requestWorkKind);

                CustomXmlPart customXml = main.AddCustomXmlPart(CustomXmlPartType.CustomXml);
                using (var dataStream = dataSource.ToStream())
                {
                    customXml.FeedData(dataStream);
                }

                var xmlDocument = new XmlDocument();
                using (var dataStream = dataSource.ToStream())
                {
                    xmlDocument.Load(dataStream);
                }
                var nsmgr = new XmlNamespaceManager(xmlDocument.NameTable);
                nsmgr.AddNamespace(DocumentDataSourceNamespace, "http://www.SCSISystem.ru/Schemas/PrintRequests");

                RemoveRepeatingSectionControls(main, xmlDocument, nsmgr);

                main.Document.Save();
            }
            return templateDocument;
        }

        private static MemoryStream GetWordTemplate(string templateName)
        {
            if (!PathsToTemplates.ContainsKey(templateName))
                throw new NotImplementedException("Данный шаблон не найден");

            var ms = new MemoryStream();
            var bytes = File.ReadAllBytes(PathsToTemplates[templateName]);
            ms.Write(bytes, 0, bytes.Length);

            return ms;
        }
       
        private static string _templatesFolder = Utils.GetPhisicalPath(ConfigurationManager.AppSettings["ReportTemplatesPath"]);
        private static Dictionary<string, string> _pathsToTemplates;
        private static Dictionary<string, string> PathsToTemplates
        {
            get
            {
                if (_pathsToTemplates == null)
                {
                    if (!Directory.Exists(_templatesFolder))
                    {
                        _templatesFolder = PathHelper.GetFullPath(_templatesFolder);
                    }
                    _pathsToTemplates = Directory.GetFiles(_templatesFolder).ToDictionary(Path.GetFileNameWithoutExtension, item => item);
                }
                return _pathsToTemplates;
            }
        }

        public static void RemoveRepeatingSectionControls(MainDocumentPart mainDocumentPart, XmlDocument document, XmlNamespaceManager nsmgr)
        {
            List<OpenXmlElement> sdtPrList =
                mainDocumentPart.Document.Descendants<SdtProperties>()
                                .Where(q => q.Descendants().Any(t => t.LocalName == "repeatingSection"))
                                .Select(q => q.Parent).ToList();
            foreach (var sdtPr in sdtPrList)
            {
                RemoveRepeatingSectionControl(sdtPr, document, nsmgr);
            }
        }

        private static void RemoveRepeatingSectionControl(OpenXmlElement blockWithRepeating, XmlDocument document, XmlNamespaceManager nsmgr)
        {
            var mainContainer = blockWithRepeating.Parent;
            var dataBinding = blockWithRepeating.GetFirstChild<SdtProperties>().ChildElements.First(q => q.LocalName == "dataBinding");
            var wns = blockWithRepeating.NamespaceUri;
            string xpath = dataBinding.GetAttribute(XpathAttrName, wns).Value;
            var collection = document.DocumentElement.SelectNodes(xpath.Replace("/" + DefaultXpathNamespace + ":", "/" + DocumentDataSourceNamespace + ":"), nsmgr);
            if (collection == null)
                return;

            var count = collection.Count;

            var repeatItemContent = blockWithRepeating.ChildElements.First(q => q.LocalName == SdtContentName).FirstChild.ChildElements.First(q => q.LocalName == SdtContentName);
            if (repeatItemContent.FirstChild == null)
                return;

            for (int i = 1; i <= count; i++)
            {
                var contentTemplate = (OpenXmlElement)repeatItemContent.FirstChild.Clone();
                foreach (var templateDataBinding in contentTemplate.Descendants<DataBinding>())
                {
                    var xpathAttr = templateDataBinding.GetAttribute(XpathAttrName, wns);
                    xpathAttr.Value = xpathAttr.Value.Replace(xpath + "[1]", xpath + "[" + i + "]");
                    templateDataBinding.RemoveAttribute(XpathAttrName, wns);
                    templateDataBinding.SetAttribute(xpathAttr);
                }
                mainContainer.InsertBefore(contentTemplate, blockWithRepeating);
            }
            blockWithRepeating.Remove();
        }

        private const string XpathAttrName = "xpath";
        private const string SdtContentName = "sdtContent";
        private const string DocumentDataSourceNamespace = "ds";
        private const string DefaultXpathNamespace = "ns0";
    }
}